/*
 * MIT License
 * 
 * Copyright (c) 2017 wen.gu <454727014@qq.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/***************************************************************************
* Name: tiny_parcel.c
*
* Purpose: parcel operation implementation
*
* Developer:
*   wen.gu , 2016-12-09
*
* TODO:
*
***************************************************************************/
#include <stdio.h>
#include <string.h>

#include "general_error.h"
#include "tiny_parcel.h"


/***************************************************************************
*
* macro define
*
***************************************************************************/
#define LOGE printf
#define LOGD printf
/***************************************************************************
*
* data structure define
*
***************************************************************************/


/***************************************************************************
*
* inner API define
*
***************************************************************************/

static inline GS32 tfParcelWriteCommon(GU08* dst, GU32 dst_size, GU32* pos,  const void* data, GU32 len)
{
    GS32 ret = G_ErrorBadParameter;

    if (data && (len > 0))
    {
        if ((*pos + len) <= dst_size)
        {
            memcpy(dst, data, len);
            *pos += len;
            ret = G_OK;
        }
        else
        {
            LOGE("doesn't enough data or space(pos+len(%d) < size(%d)) \n", (*pos + len), dst_size);
            ret = G_ErrorOverflow;
        }
    }

    return ret;
}


/***************************************************************************
*
* API define
*
***************************************************************************/

GS32 tfParcelWrite(tiny_parcel_t* parcel, const void* data, GU32 len)
{
    return tfParcelWriteCommon(parcel->data + parcel->pos, parcel->size, &(parcel->pos), data, len);
}

GS32 tfParcelWriteInt32(tiny_parcel_t* parcel, GS32 value)
{
    return tfParcelWrite(parcel, (const void*)&value, sizeof(value));
}

GS32 tfParcelWriteInt64(tiny_parcel_t* parcel, GS64 value)
{
    return tfParcelWrite(parcel, (const void*)&value, sizeof(value));
}

GS32 tfParcelWriteFloat(tiny_parcel_t* parcel, GFLT value)
{
    return tfParcelWrite(parcel, (const void*)&value, sizeof(value));
}

GS32 tfParcelWriteString(tiny_parcel_t* parcel, const char* value)
{
    return tfParcelWrite(parcel, (const void*)value, value ? (strlen(value) + 1) : 0);
}

GS32 tfParcelRead(tiny_parcel_t* parcel, void* out_data, GU32 len)
{
    return tfParcelWriteCommon(out_data, parcel->size, &(parcel->pos), parcel->data + parcel->pos, len);
}

GS32 tfParcelReadInt32(tiny_parcel_t* parcel)
{
    GS32 value = 0;
    tfParcelRead(parcel, (void*)&value, sizeof(value));

    return value;
}

GS64 tfParcelReadInt64(tiny_parcel_t* parcel)
{
    GS64 value = 0;
    tfParcelRead(parcel, (void*)&value, sizeof(value));

    return value;
}

GFLT tfParcelReadFloat(tiny_parcel_t* parcel)
{
    GFLT value = 0;
    tfParcelRead(parcel, (void*)&value, sizeof(value));

    return value;
}

GSTR tfParcelReadString(tiny_parcel_t* parcel)
{
    GSTR value = NULL;
    GU32 avail = parcel->size - parcel->pos;

    if (avail > 0)
    {
        GSTR str = (GSTR)(parcel->data + parcel->pos);
        // is the string's trailing NUL within the parcel's valid bounds?
        GSTR eos = memchr(str, '\0', avail);

        if (eos)
        {
            GU32 len = eos - str;
            value = str;
            parcel->pos += (len + 1); /** + 1, indicate skip '\0' */
        }
    }

    return value;
}

GS32 tfParcelInitialize(tiny_parcel_t* parcel, void* data, GU32 len)
{
    GS32 ret = G_ErrorBadParameter;

    if (parcel && data && (len > 0))
    {
        parcel->data = data;
        parcel->size = len;
        parcel->pos = 0;
        ret = G_OK;
    }
    else
    {
        LOGE("bad parameter\n");
    }

    return ret;
}



